<script lang="ts" setup name="ECustomTable">
import { PropType, reactive, ref, computed, nextTick, watch, unref, onBeforeMount } from 'vue'
import { propTypes } from '@/utils/propTypes'
import { ElTable, ElForm } from 'element-plus'
import Sortable from 'sortablejs'
import { Column, TableState } from './type'
import eTableSettingDialog from './eTableSettingDialog.vue'
// import { getListSetting } from '@/api/system/user'

// Props 定义
const props = defineProps({
  selection: propTypes.bool.def(false), // 是否显示选择列
  index: propTypes.bool.def(false), // 是否显示序号列
  modelValue: propTypes.bool.def(false), // 是否显示弹窗
  loading: propTypes.bool.def(false), // 是否显示加载中
  title: propTypes.string.def(''), // 表格标题
  canSetting: propTypes.bool.def(false), // 是否可以设置列
  tableData: propTypes.array.def([]), // 表格数据
  borderBottom: propTypes.bool.def(false), // 是否显示表头下边框
  editStatus: propTypes.bool.def(false), // 是否显示编辑状态
  rules: propTypes.object.def({}), // 表单验证规则
  showOverflowTooltip: propTypes.bool.def(true), // 是否显示溢出提示
  paddingLR: propTypes.bool.def(false), //仅仅针对列表页的padding
  tableHeader: {
    // 表头列配置
    type: Array as PropType<Column[]>,
    default: () => []
  },
  uniqueKey: propTypes.string.def(''), // 系统表格唯一键，用于存储/读取表格配置
  columnEvents: propTypes.object.def({}), // 事件配置
  selectable: propTypes.func.def(undefined), // 是否可选择
  selectionWidth: propTypes.string.def('55'), // 选择列宽度
  getListSettingFunc: propTypes.func.def(undefined), // 获取表格配置
})

// 表格状态管理
const tableState = reactive<TableState>({
  data: [...props.tableData], // 表格数据
  columns: [...props.tableHeader] // 表头列原始配置
})
// 表格引用
const tableRef = ref<InstanceType<typeof ElTable>>()

// 列配置管理
const columnConfig = reactive({
  showDialog: false, // 弹窗是否显示
  configData: [] as Column[], // 全量列表配置数据
  dialogConfigData: [] as Column[], // 弹窗列配置数据
  showColumnOrder: [] as string[], // 显示列顺序
  columnOrder: [] as string[] // 列顺序
})
// 监听表格数据变化
watch(
  () => props.tableData,
  (newData) => {
    tableState.data = [...newData]
  },
  { deep: true }
)

// 列配置管理
// 初始化列配置
const init = () => {
  // 初始化列配置及顺序
  initVisibleColumns()
  if (props.canSetting) {
    // 仅针对可显示表头进行排序
    nextTick(() => initSortable())
  }
}

// 表格是否固定项
const isFixed = computed(() => {
  return columnConfig.configData.some((item) => item.fixType)
})

// 从缓存或者接口获取表格配置
const pageLoading = ref(false)
const getTableConfig = async (): Promise<Column[]> => {
  pageLoading.value = true
  let config: Column[] = await new Promise((resolve) => {
    /* 不能从缓存中获取，因为没有携带用户信息 */
    // let config = sessionStorage.getItem(props.uniqueKey) // 从缓存获取表格配置
    // if (!config) {
    // 直接从接口获取
    if (!props.uniqueKey || !props.getListSettingFunc) return  resolve([...props.tableHeader])
    props.getListSettingFunc({
      settingKey: props.uniqueKey
    }).then((res) => {
      if (res?.settingValue) {
        resolve(JSON.parse(res.settingValue))
      } else {
        resolve([...props.tableHeader].map((col) => ({ ...col })))
      }
    })
    // } else {
    //   resolve(JSON.parse(config))
    // }
  })
  pageLoading.value = false
  return config
}

// 根据组件入参初始化列配置
const initVisibleColumns = async () => {
  // 获取表格配置
  let config: Column[] = []
  if (props.uniqueKey) {
    // 获取表格配置
    config = await getTableConfig()
  }
  // 将配置数据转换为对象并重新排序
  const configProps = {}
  config.forEach((col, index) => {
    col.sortNo = index
    configProps[col.prop] = col
  })
  // 遍历原始表头配置，将配置数据转换为对象并重新排序
  // 保留props.tableHeader中的的原始数据,仅替换排序和显示
  columnConfig.configData = [...props.tableHeader]
    .map((col) => {
      let newCol = { ...col }
      if (configProps[col.prop]) {
        // 如果配置数据存在，则使用配置数据
        newCol.show = configProps[col.prop].show
        newCol.sortNo = configProps[col.prop].sortNo
      } else {
        // 如果配置数据不存在，则使用原始表头配置
        newCol.show = true
        newCol.sortNo = newCol.sortNo ?? -1
      }
      return newCol
    })
    .sort((a: Column, b: Column) => {
      // 根据sortNo排序
      return (a.sortNo ?? 0) - (b.sortNo ?? 0)
    })
  // 获得初始化列表顺序
  columnConfig.columnOrder = getColumnOrder(columnConfig.configData)
}

// 初始化表格列顺序
const getColumnOrder = (data: any[]) => {
  // 获取左侧固定列
  const leftFixedColumns = data
    .filter((col) => col.prop && col.show !== false && col.fixType === 'left')
    .map((col) => col.prop)

  // 获取正常列
  const normalColumns = data
    .filter((col) => col.prop && col.show !== false && !col.fixType)
    .map((col) => col.prop)

  // 获取右侧固定列
  const rightFixedColumns = data
    .filter((col) => col.prop && col.show !== false && col.fixType === 'right')
    .map((col) => col.prop)

  return [...leftFixedColumns, ...normalColumns, ...rightFixedColumns]
}

/**
 * 初始化表格拖拽排序功能
 */
function initSortable() {
  const el = tableRef.value?.$el.querySelector('.el-table__header-wrapper thead tr')
  if (!el) return

  Sortable.create(el, {
    animation: 300, // 动画时长
    handle: '.draggable-column', // 拖拽元素选择器
    ghostClass: 'sortable-ghost', // 拖动时的样式
    dragClass: 'sortable-drag', // 拖动时的样式
    draggable: '.draggable-column', // 可拖拽的元素
    filter: '.el-table-fixed-column--left,.el-table-fixed-column--right', // 过滤元素
    onMove: function (evt) {
      // 如果目标元素包含 el-table-fixed-column--left， el-table-fixed-column--right 类，则阻止移动
      return (
        !evt.related.classList.contains('el-table-fixed-column--left') &&
        !evt.related.classList.contains('el-table-fixed-column--right')
      )
    },
    onEnd: ({ newIndex, oldIndex }) => {
      if (newIndex === undefined || oldIndex === undefined) return
      let len = 0
      if (props.selection) len++
      if (props.index) len++

      // 需要考虑选择列和序号列的偏移
      const realOldIndex = oldIndex - len // 减去选择列和序号列
      const realNewIndex = newIndex - len

      // 更新列顺序
      const newOrder = [...columnConfig.columnOrder]
      const [moved] = newOrder.splice(realOldIndex, 1)
      newOrder.splice(realNewIndex, 0, moved)
      columnConfig.columnOrder = newOrder // 表格数据根据排序顺序重新计算列表项
    }
  })
}

// 计算排序后的列
const sortedColumns = computed(() => {
  // 获取所有可见列
  const visibleColumns = columnConfig.configData.filter((item) => item.show !== false)

  // 如果没有自定义顺序，返回所有可见列
  if (columnConfig.columnOrder.length === 0) {
    return visibleColumns
  }

  // 创建一个新的排序后的列数组
  const orderedColumns: Column[] = []

  // 按照 columnOrder 的顺序排序添加可见列
  columnConfig.columnOrder.forEach((prop) => {
    const column = visibleColumns.find((col) => col.prop === prop)
    if (column && column.show !== false) {
      orderedColumns.push(column)
    }
  })
  // 如果每列都设置了指定宽度，则将最后一列的width替换为minWidth
  if (
    orderedColumns.filter((item) => item.width).length === orderedColumns.length &&
    orderedColumns.length > 0
  ) {
    const lastColumn = orderedColumns[orderedColumns.length - 1]
    lastColumn.minWidth = lastColumn.width
    delete lastColumn.width
  }
  return orderedColumns
})

// 格式化表格值
const formatColumnValue = (column, row) => {
  if (column.filterConfig?.formatter) {
    return column.filterConfig.formatter(
      row[column.prop],
      ...(column.filterConfig.extraData || [column.filterConfig.options] || [])
    )
  } else if (column.filterConfig?.options && column.filterConfig?.options.length > 0) {
    return column.filterConfig.options.find((item) => item.value === row[column.prop])?.label
  }
  return row[column.prop]
}
// element form 实例
const elFormRef = ref<ComponentRef<typeof ElForm>>()
const getElFormRef = (): ComponentRef<typeof ElForm> => {
  return unref(elFormRef) as ComponentRef<typeof ElForm>
}
defineExpose({ getElFormRef, tableRef })
// 生命周期钩子
onBeforeMount(() => {
  init()
})

const tableSettingDialogRef = ref()
// 打开列设置弹窗
const openDialog = () => {
  tableSettingDialogRef.value.openDialog([...tableState.columns])
}

// 重新应用列设置
const handleApplyColumns = (newConfigData: Column[]) => {
  // 保存列表设置到本地
  // if (props.uniqueKey) {
  //   sessionStorage.setItem(props.uniqueKey, JSON.stringify(newConfigData))
  // }
  // 更新表头顺序
  columnConfig.columnOrder = getColumnOrder(newConfigData)
  // 更新表头配置数据
  columnConfig.configData = [...newConfigData]
}

// 绑定事件
const getEventBindings = (events, row) => {
  const handlers = {}
  if (events) {
    events.forEach((event) => {
      if (props.columnEvents[event.handler]) {
        handlers[event.name] = (...args) => props.columnEvents[event.handler](...args, row)
      }
    })
  }
  return handlers
}
</script>

<template>
  <div >
    <slot name="title">
      <div class="table-title" :class="{ 'border-bottom': borderBottom, 'p-x-20px': paddingLR }"
        v-if="title || $slots['custom-title'] || $slots['custom-btn']">
        <div class="flex items-center">
          <slot name="custom-title">
            <span class="table-title-text">{{ title }}</span>
          </slot>
        </div>
        <div class="flex items-center">
          <slot name="custom-btn"> </slot>
          <e-button @click="openDialog" v-if="canSetting" class="ml-2">
            <Icon :size="16" icon="ep:setting" /> 列表设置
          </e-button>
        </div>
      </div>
    </slot>
    <div class="table-body" :class="{ 'p-x-20px': paddingLR }">
      <el-form ref="elFormRef" :model="tableData" :rules="rules">
        <el-table ref="tableRef" class="custom-table" :data="tableState.data" v-bind="$attrs" v-loading="loading"
          :show-overflow-tooltip="showOverflowTooltip" :tooltip-options="{
            popperClass: 'table-tooltip-popper'
          }">
          <!-- 选择列 -->
          <el-table-column type="selection" :fixed="isFixed" v-if="selection" :width="selectionWidth"
            :selectable="selectable ? selectable : undefined" />
          <!-- 序号列 -->
          <el-table-column type="index" label="序号" :fixed="isFixed" v-if="index" width="65" />
          <!-- 数据列 -->
          <el-table-column v-for="column in sortedColumns" :key="column.prop" :prop="column.prop" :label="column.label"
            :sortable="column.sortable" class-name="draggable-column" :align="column.alignType"
            :header-align="column.headerAlign || column.alignType" :fixed="column.fixType || undefined"
            :width="column.width" :type="column.type" :min-width="column.minWidth"
            :show-overflow-tooltip="column.showTooltip != undefined ? column.showTooltip : true"
            :tooltip-formatter="column.tooltipFormatter">
            <template #header>
              <slot :name="`header-${column.prop}`" :column="column">
                <div class="table-header-container">
                  <span>
                    {{ column.label }}
                    <span v-if="column.required" class="required-icon">*</span>
                  </span>
                </div>
              </slot>
            </template>
            <template #default="scope">
              <!-- <span v-if="column.prop === 'No'">
                {{ scope.row.No }}
              </span> -->
              <!-- 输入框 -->
              <el-form-item v-if="column.prop != 'No'" :prop="`${scope.$index}.${column.prop}`"
                :rules="rules[column.prop]" :show-message="false">
                <slot :name="column.prop" :row="scope.row" :index="scope['$index']">
                  <!-- 输入框 -->
                  <el-input v-if="
                    (editStatus || scope.row.editStatus) &&
                    !scope.row.canNoEditField?.includes(column.prop) &&
                    column.filterConfig?.type === 'input'
                  " v-model="scope.row[column.prop]" :maxLength="column.filterConfig.maxLength"
                    :placeholder="column.filterConfig.placeholder" :formatter="column.filterConfig?.formatter"
                    :parser="column.filterConfig?.parser" :disabled="column.filterConfig?.disabled"
                    :class="{ 'price-input': column?.alignType === 'right' }"
                    v-bind="getEventBindings(column.filterConfig?.events, scope.row)" />
                  <!-- 文本域 -->
                  <el-input v-else-if="
                    (editStatus || scope.row.editStatus) &&
                    !scope.row.canNoEditField?.includes(column.prop) &&
                    column.filterConfig?.type === 'textarea'
                  " v-model="scope.row[column.prop]" type="textarea" :maxLength="column.filterConfig.maxLength"
                    :autosize="column.filterConfig.autosize || { minRows: 1, maxRows: 3 }"
                    :placeholder="column.filterConfig.placeholder" :formatter="column.filterConfig?.formatter"
                    :parser="column.filterConfig?.parser" :disabled="column.filterConfig?.disabled"
                    v-bind="getEventBindings(column.filterConfig?.events, scope.row)" />
                  <!-- 下拉框 -->
                  <el-select v-else-if="
                    (editStatus || scope.row.editStatus) &&
                    !scope.row.canNoEditField?.includes(column.prop) &&
                    column.filterConfig?.type === 'select'
                  " v-model="scope.row[column.prop]" :placeholder="column.filterConfig.placeholder"
                    :disabled="column.filterConfig?.disabled"
                    v-bind="getEventBindings(column.filterConfig?.events, scope.row)">
                    <el-option v-for="item in column.filterConfig.options" :key="item.value" :label="item.label"
                      :value="item.value" />
                  </el-select>
                  <!-- 日期选择器 -->
                  <el-date-picker v-else-if="
                    (editStatus || scope.row.editStatus) &&
                    !scope.row.canNoEditField?.includes(column.prop) &&
                    column.filterConfig?.type === 'date'
                  " v-model="scope.row[column.prop]" class="value-input"
                    :format="column.filterConfig?.format || 'YYYY-MM-DD'"
                    :value-format="column.filterConfig?.valueFormat || 'YYYY-MM-DD HH:mm:ss'"
                    :placeholder="column.filterConfig.placeholder" :disabled="column.filterConfig?.disabled"
                    v-bind="getEventBindings(column.filterConfig?.events, scope.row)" />
                  <!-- 日期范围选择器 -->
                  <el-date-picker v-else-if="
                    (editStatus || scope.row.editStatus) &&
                    !scope.row.canNoEditField?.includes(column.prop) &&
                    column.filterConfig?.type === 'dateRange'
                  " v-model="scope.row[column.prop]" class="value-input" type="daterange" format="YYYY-MM-DD"
                    value-format="YYYY-MM-DD" range-separator="To" start-placeholder="Start date"
                    end-placeholder="End date" :placeholder="column.filterConfig.placeholder"
                    :disabled="column.filterConfig?.disabled"
                    v-bind="getEventBindings(column.filterConfig?.events, scope.row)" />
                  <e-remote-select v-model="scope.row[column.prop]" v-else-if="
                    (editStatus || scope.row.editStatus) &&
                    !scope.row.canNoEditField?.includes(column.prop) &&
                    column.filterConfig?.type === 'remoteSelect'
                  " :placeholder="column.filterConfig.placeholder" :initOptions="column.filterConfig.options"
                    :showFiled="column.filterConfig.showFiled" :query-api="column.filterConfig.queryApi"
                    :type="column.filterConfig.remoteType" :disabled="column.filterConfig?.disabled"
                    v-bind="column.filterConfig.attrs" />
                  <template v-else>
                    {{ formatColumnValue(column, scope.row) }}
                  </template>
                </slot>
                <!-- 隐藏值:用于表格项输入控件tooltip展示 -->
                <span style="display: none">{{ formatColumnValue(column, scope.row) }}</span>
              </el-form-item>
            </template>
          </el-table-column>
        </el-table>
      </el-form>
    </div>
  </div>

  <!-- 列设置弹窗 -->
  <eTableSettingDialog ref="tableSettingDialogRef" :config-data="columnConfig.configData" :unique-key="uniqueKey"
    @apply="handleApplyColumns" />
</template>

<style lang="scss" scoped>
.table-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: #000000;
  height: 56px;
  line-height: 56px;

  .table-title-text {
    font-family: PingFang SC;
    font-size: 18px;
    font-weight: 600;
    line-height: 25.2px;
    text-align: left;
    text-underline-position: from-font;
    text-decoration-skip-ink: none;
    color: #000000;
  }
}

.border-bottom {
  border-bottom: 1px solid #cccccc;
  margin-bottom: 20px;
}

:deep(.custom-table) {
  .el-table__header {
    .required-icon {
      color: red;
    }

    .cell {
      display: inline-flex;
      align-items: center;

      .table-header-container {
        display: inline-flex;
        flex: 1;
        align-items: center;
        // justify-content: space-between;
      }
    }
  }
}

// :deep(.el-button.is-text) {
//   padding: 8px 4px;
//   margin-left: 0;
// }

:deep(.sortable-ghost) {
  opacity: 0.5;
  background: #a8abb2;
}

:deep(.el-table__row) {
  .el-table__cell {
    padding: 0;
    height: 40px;
    line-height: 40px;
  }

  .el-form-item {
    margin-bottom: 0;
    margin-right: 0;
    display: inline-flex;
    max-width: 100%;
    width: 100%;

    .el-form-item__content {
      display: inline-block; // 解决表格列不显示tooltip问题
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
    }
  }
}
</style>

<style lang="scss">
.table-tooltip-popper {
  max-width: 600px;
}
</style>
